package coupon

import (
	"context"
	"strconv"

	"mall/common/globalkey"
	"mall/common/modelx"
	"mall/common/moneyx"
	"mall/common/utils/pointy"
	enum "mall/service/backend/common/enum/promotion"
	"mall/service/backend/common/errorx"
	"mall/service/backend/common/i18n"
	"mall/service/promotion/model"
	"mall/service/promotion/rpc/internal/svc"
	"mall/service/promotion/rpc/internal/utils/errorhandler"
	"mall/service/promotion/rpc/types/promotion"

	"github.com/zeromicro/go-zero/core/logx"
)

type BackendGetCouponTemlateByIdLogic struct {
	ctx    context.Context
	svcCtx *svc.ServiceContext
	logx.Logger
}

func NewBackendGetCouponTemlateByIdLogic(ctx context.Context, svcCtx *svc.ServiceContext) *BackendGetCouponTemlateByIdLogic {
	return &BackendGetCouponTemlateByIdLogic{
		ctx:    ctx,
		svcCtx: svcCtx,
		Logger: logx.WithContext(ctx),
	}
}

func (l *BackendGetCouponTemlateByIdLogic) BackendGetCouponTemlateById(in *promotion.CouponTemlateIdReq) (*promotion.CouponTemlateInfo, error) {
	if in.Id == 0 {
		return nil, errorx.NewInvalidArgumentError(i18n.ValidationError)
	}

	res, err := l.svcCtx.CouponTemplate.FindOne(l.ctx, in.Id)
	if err != nil {
		return nil, errorhandler.DefaultRepositoryError(l.Logger, err, in)
	}

	var meta []*promotion.MetaInfo
	if in.WithMeta != nil && *in.WithMeta > 0 {
		filterMap := make(map[string]map[string][]any)
		filterMap[model.PromotionCouponMetumColumns.CouponTemplateID] = map[string][]any{
			"equalTo": {in.Id},
		}
		list, _, err := l.svcCtx.CouponTemplate.GetMeta(l.ctx, model.M{}, -1, filterMap)
		if err != nil {
			return nil, errorhandler.DefaultRepositoryError(l.Logger, err, in)
		}

		if len(list) > 0 {
			for _, v := range list {
				if v.MetaKey == "_thumbnail_id" || v.MetaKey == "_thumbnail_url" {
					continue
				}

				if len(v.MetaKey) > 0 && v.MetaValue.Valid {
					meta = append(meta, &promotion.MetaInfo{
						Id:    &v.MetaID,
						Key:   &v.MetaKey,
						Value: &v.MetaValue.String,
					})
				}
			}
		}
	}

	var media []*promotion.MediaInfo
	if in.WithMedia != nil && *in.WithMedia > 0 {
		filterMap := make(map[string]map[string][]any)
		filterMap[model.PromotionAttachmentRelationshipColumns.ObjectID] = map[string][]any{
			"equalTo": {in.Id},
		}
		filterMap[model.PromotionAttachmentRelationshipColumns.ObjectType] = map[string][]any{
			"equalTo": {globalkey.AttachmentLogTypePromotionCoupon},
		}
		var orderBy string = model.PromotionAttachmentRelationshipColumns.AttachmentThumbnail + " DESC, " +
			model.PromotionAttachmentRelationshipColumns.AttachmentOrder
		list, _, err := l.svcCtx.CouponTemplate.GetMedia(l.ctx, model.M{
			"orderBy": orderBy,
		}, -1, filterMap)
		if err != nil {
			return nil, errorhandler.DefaultRepositoryError(l.Logger, err, in)
		}

		if len(list) > 0 {
			for _, v := range list {
				media = append(media, &promotion.MediaInfo{
					Uid:       &v.AttachmentRelationshipID,
					Id:        pointy.GetPointer(strconv.FormatInt(int64(v.AttachmentID), 10)),
					Thumbnail: pointy.GetPointer(uint32(v.AttachmentThumbnail)),
					Order:     pointy.GetPointer(uint32(v.AttachmentOrder)),
					Uri:       &v.AttachmentSource,
					Url:       &v.AttachmentImageURL,
					AltText:   &v.AttachmentImageAlt,
					MetaData:  &v.AttachmentImageMeta,
				})
			}
		}
	}

	var threshhold string
	switch res.Mode {
	case enum.PromotionCouponModeAmount:
		threshhold = moneyx.FormatAmount(int64(res.Threshhold))
	case enum.PromotionCouponModeNumber:
		threshhold = strconv.FormatInt(int64(res.Threshhold), 10)
	}
	var discountValue string
	var regions *string
	switch res.DiscountMode {
	case enum.PromotionCouponRuleAmount, enum.PromotionCouponRuleFixedPrice:
		discountValue = moneyx.FormatAmount(int64(res.DiscountValue))
	case enum.PromotionCouponRuleDiscount:
		discountValue = strconv.FormatInt(int64(res.DiscountValue), 10)
	case enum.PromotionCouponRuleOrderFreeShipping, enum.PromotionCouponRuleProductFreeShipping:
		if res.Regions.Valid {
			regions = pointy.GetPointer(string(res.Regions.JSON))
		}
	}

	var gemPrice *string
	if res.GemPrice > 0 {
		gemPrice = pointy.GetPointer(moneyx.FormatGem(int64(res.GemPrice)))
	}

	return &promotion.CouponTemlateInfo{
		Id:                &res.ID,
		Name:              &res.Name,
		Slug:              &res.Remark,
		Desc:              &res.Description,
		FilteredDesc:      &res.DescriptionFiltered,
		Condition:         pointy.GetPointer(uint32(res.Mode)),
		ConditionValue:    pointy.GetPointer(threshhold),
		DiscountMode:      pointy.GetPointer(uint32(res.DiscountMode)),
		DiscountValue:     pointy.GetPointer(discountValue),
		ScopeType:         pointy.GetPointer(uint32(res.ScopeType)),
		GemPrice:          gemPrice,
		ApplyStartedAt:    pointy.GetPointer(modelx.FormatNullDotTime(res.ApplyStartedAt, "")),
		ApplyEndedAt:      pointy.GetPointer(modelx.FormatNullDotTime(res.ApplyEndedAt, "")),
		ExpireMode:        pointy.GetPointer(uint32(res.ExpireMode)),
		ExpireValue:       pointy.GetPointer(uint32(res.ExpireValue)),
		StartedAt:         pointy.GetPointer(modelx.FormatNullDotTime(res.StartedAt, "")),
		EndedAt:           pointy.GetPointer(modelx.FormatNullDotTime(res.EndedAt, "")),
		Sort:              pointy.GetPointer(uint32(res.Sort)),
		Status:            pointy.GetPointer(uint32(res.Status)),
		MemberRestriction: &res.MemberRestriction,
		CouponType:        pointy.GetPointer(uint32(res.CouponType)),
		MutexType:         pointy.GetPointer(uint32(res.MutexType)),
		Count:             pointy.GetPointer(uint32(res.Count)),
		PerLimit:          pointy.GetPointer(uint32(res.PerLimit)),
		Step:              pointy.GetPointer(uint32(res.CreateStep)),
		CreatedAt:         pointy.GetPointer(modelx.FormatTime(res.CreatedAt, "")),
		UpdatedAt:         pointy.GetPointer(modelx.FormatTime(res.UpdatedAt, "")),
		DeletedAt:         pointy.GetPointer(modelx.FormatNullDotTime(res.DeletedAt, "")),
		Regions:           regions,
		Meta:              meta,
		Media:             media,
	}, nil
}
